<?php

namespace application\service;

use application\service\BaseService;
use application\model\ImageModel;
use application\util\TextUtil;
use application\entity\Response;
use ReflectionClass;
use stdClass;

class DataService extends BaseService {

    private $folderPath = "application/entity/db";
    private $imageModel;

    public function __construct() {
        $this->imageModel = new ImageModel();
    }

    public function getTable() {
        $dbTables = $this->imageModel->getTables();
        $tables = array();
        $tables = $this->readEntitys();
        foreach ($tables as $table) {
            if (in_array($table->table, $dbTables)) {
                $table->create = true;
            }
        }
        return $tables;
    }

    public function getTableInfo($className) {
        $tables = $this->readEntitys();
        $table = null;
        foreach ($tables as $tbl) {
            if ($tbl->class == $className) {
                $table = $this->readEntityClass($tbl->path);
            }
        }
        return $table;
    }

    private function readEntitys() {
        $entitys = array();
        $files = TextUtil::read_all_files($this->folderPath);
        if ($files["files"] != null && count($files["files"]) > 0) {
            $files = $files["files"];
            foreach ($files as $filePath) {
                $cls = $this->readEntityClass($filePath);
                $cls->create = false;
                if ($cls->table != null) {
                    $entitys[] = $cls;
                }
            }
        }
        return $entitys;
    }

    private function readEntityClass($filePath) {
        $cls = null;
        if (file_exists($filePath)) {
            require_once $filePath;
            $className = basename($filePath, ".php");
            $class = new ReflectionClass('\application\entity\db\\' . $className);
            $cls = new stdClass();
            $cls->table = $this->getTableName($class->getDocComment());

            $cls->class = $className;
            $cls->path = $filePath;
            $cls->col = $this->readProperties($class);
        }
        return $cls;
    }

    private function readProperties($class = null) {
        $pfs = array();
        $properties = $class->getProperties();
        foreach ($properties as $property) {
            $document = $property->getDocComment();
            $col = new stdClass();
            $col->name = $property->getName();
            $col->comment = $this->getComment($document);
            $col->properties = $this->getCol($document);
            $col->remove = $this->getRemove($document);
            $col->id = $this->getId($document);
            $pfs[] = $col;
        }
        return $pfs;
    }

    private function getTableName($string = null) {
        preg_match('/\@document\((.*)\)/', $string, $matches);
        return @$matches[1];
    }

    private function getComment($string = null) {
        preg_match('/\@comment\((.*)\)/', $string, $matches);
        return @$matches[1];
    }

    private function getRemove($string = null) {
        return preg_match('/\@remove/', $string);
    }

    private function getId($string = null) {
        return preg_match('/\@id/', $string);
    }

    private function getCol($string = null) {
        preg_match('/\@col\((.*)\)/', $string, $matches);
        try {
            $matches = explode(",", @$matches[1]);
            $dataCol = array();
            foreach ($matches as $val) {
                $col = explode("=", trim($val));
                $pfs = new stdClass();
                $pfs->key = $col[0];
                $pfs->value = $col[1];
                $dataCol[] = $pfs;
            }
            return @$dataCol;
        } catch (Exception $exc) {
            return null;
        }
    }

    public function createTable($className) {
        $class = $this->getTableInfo($className);
        if ($class == null) {
            return new Response(false, "Không tìm thấy thông tin cấu hình bảng" . $className);
        }
        $primary = "id";
        $class->table = '`' . $class->table . '`';
        $sql = "CREATE TABLE IF NOT EXISTS " . $class->table . "( ";
        $unique = array();
        $index = array();
        $fulltext = array();
        foreach ($class->col as $col) {
            if ($col->remove) {
                continue;
            }
            $dataCol = array();
            foreach ($col->properties as $property) {
                $dataCol[$property->key] = $property->value;
            }
            $name = (@$dataCol["name"] != "") ? trim(@$dataCol["name"]) : $col->name;
            $name = '`' . $name . '`';
            if (@$dataCol["index"] == 'unique') {
                $unique[] = $name;
                $index[] = $name;
            } else if (@$dataCol["index"] == 'index') {
                $index[] = $name;
            }
            if (@$dataCol["fulltext"] == true) {
                $fulltext[] = $name;
                if (!in_array($name, $index))
                    $index[] = $name;
            }
            if ($col->id) {
                $primary = $name;
            }
            $sql .= $name . " ";
            $sql .= (@$dataCol['type'] == 'varchar') ? @$dataCol['type'] . '(' .
                    (@$dataCol['length'] != '' ? @$dataCol['length'] : 1) . ') ' : @$dataCol['type'] . ' ';
            if (@$dataCol["identity"]) {
                $sql .= 'AUTO_INCREMENT ';
            }
            $sql .= (@$dataCol["null"]) ? 'null ' : 'not null ';
            if (@$dataCol["default"] != '') {
                $sql .= 'default ';
                switch (@$dataCol["default"]) {
                    case 'DATE_TIME' :
                        $date = new DateTime();
                        $sql .= $date->getTimestamp() . ' ';
                        break;
                    default :$sql .= ' ' . @$dataCol["default"] . ' ';
                }
            }
            $sql .= ',';
        }

        $sql .= " PRIMARY KEY (" . $primary . ")" .
                "); ";
        $succsess = $this->imageModel->query($sql);
        if ($this->imageModel->error() != '') {
            return new Response(false, "Không thể thêm bảng " . $class->table . ', ' . $this->imageModel->error());
        }
        if ($index != null && count($index) > 0) {
            $index = "ALTER TABLE " . $class->table . " ADD INDEX(" . implode(",", $index) . "); ";
            $succsess = $this->imageModel->query($index);
        }
        if ($unique != null && count($unique) > 0) {
            $unique = "ALTER TABLE " . $class->table . " ADD UNIQUE(" . implode(",", $unique) . "); ";
            $succsess = $this->imageModel->query($unique);
        }
        if ($fulltext != null && count($fulltext) > 0) {
            $fulltext = "ALTER TABLE " . $class->table . " ADD FULLTEXT(" . implode(",", $fulltext) . "); ";
            $succsess = $this->imageModel->query($fulltext);
        }


        if ($this->imageModel->error() != '') {
            return new Response(false, "Không thể thêm bảng " . $class->table . ', ' . $this->imageModel->error());
        }
        return new Response(true, "Tạo bảng " . $class->table . ' thành công');
    }

    /**
     * Tạo database
     * @return \application\entity\Response
     */
    public function createDatabase() {
        $databse = $this->getDatabase();
        $query = 'CREATE DATABASE IF NOT EXISTS ' . $databse . ' DEFAULT CHARACTER SET = "utf8" DEFAULT COLLATE "utf8_general_ci"';
        $this->imageModel->query($query);
        if ($this->imageModel->error() != '') {
            return new Response(false, "Không thể tạo database " . $databse . ', ' . $this->imageModel->error());
        }
        return new Response(true, "Tạo database  " . $databse . ' thành công');
    }

    /**
     * Tên database
     * @return type
     */
    public function getDatabase() {
        $db = \application\webapp\config\MainConfig::getDb();
        preg_match("/mysql:host=(.*);dbname=(.*)/", $db["connectString"], $matches);
        return trim(strtolower($matches[2]));
    }

}
